package justForFun;
import java.util.LinkedList;

import structureDonnee.Expression;
import structureDonnee.Inequalite;
import structureDonnee.Invariant;

public class Simplification {
	Invariant inv;
	// 1 suppose tous >=; variables ordered from X0 to Xn-1 (coefficant 0 if not
	// existed);
	// 2 suppose all X>=0

	double[][] matrice;// dim: (index+1)*(N+index+1)
	// each line: a0,a1,a2,...,a(n-1),c

	int N;// number of variables
	int index;// number of inequations
	Expression expr;// to see if f=expr in inv has min>=0

	// donc matrice est de taille: index*(N+1)
	public Simplification(double[][] M) {
		matrice = M;

		index = M.length;// ???????????
		N = M[0].length - index - 1;
	}

	public Simplification(Invariant system, Expression e) {

		inv = system;
		double[] c = new double[index]; // C

		LinkedList<Inequalite> clone = (LinkedList<Inequalite>)inv.listIne.clone();

		int j = 0;
		int n = 0;
		while (!clone.isEmpty()) {

			Inequalite ieq = clone.poll();
			LinkedList<Double> listexpr = ieq.expr.listExpr;
			n = listexpr.size();
			for (int i = 0; i < n - 1; i = i + 1) {
				matrice[j][i] = listexpr.poll();// a0,a1,a2,...,a(n-1)
			}
			c[j] = listexpr.poll();
			j = j + 1;
		}
		N = n - 1;
		index = j;

		for (int k = 0; k < index; k++) {
			for (int i = N; i < N + index; i++) {
				if (k == i) {
					matrice[k][N + i] = 1.;
				} else {
					matrice[k][N + i] = 0.;
				}
			}
			matrice[k][N + index] = (-1) * c[k];

		}

		// last line
		expr = e;
		LinkedList<Double> temp = (LinkedList<Double>) expr.listExpr.clone();
		double c0 = temp.pollLast();

		int i = 0;
		while (!temp.isEmpty()) {
			matrice[index][i] = ((-1) * temp.poll()); // last line!
			i++;
		}
		for (int l = 0; l < index; l++) {
			matrice[index][N + l] = 0;
		}
		matrice[index][N + index] = c0;
	}

	public double Mini() {
		// to see if f=expr in inv has min>=0
		// realisation de methode de Simplexe
		// to minimise
		// f0, ...,fn-1,C

		// to initialise expr, s.t. dim=[this.index+this.N]
		double[][] M = matrice.clone();

		// find main Colonne
		int mainC = MainColonne(M);

		if (!Check(M, mainC)) {
			return M[index][N + index + 1];
		} else {
			int mainL = MainLigne(M, mainC);
			// transformation de ligne, t.q. M[mainL][mainC]=1,
			// M[other][mainC]=0
			double diviser = M[mainL][mainC];
			for (int k = 0; k < index + N + 1; k++) {
				M[mainL][k] = M[mainL][k] / diviser;
			}
			for (int l = 0; l <= index; l++) {
				if (l != mainL) {
					for (int k = 0; k < index + N + 1; k++) {
						M[l][k] = M[l][k] - M[mainL][k] * M[l][mainC];
					}
				}
			}
			Simplification s = new Simplification(M);
			return s.Mini();

		}

	}

	public int MainColonneExpr(Expression expr) {
		// to find the main colonne: i.e. the largest

		int num = 0;// index of the biggest number
		LinkedList<Double> temp = new LinkedList<Double>();
		temp = expr.listExpr;
		temp.pollLast();// remove C

		double big = temp.peek();
		int i = 0;

		while (!temp.isEmpty()) {
			double a = temp.poll();
			if (big < a) {
				big = a;
				num = i;
			}
			i = i + 1;
		}
		return num;
	}

	public int MainColonne(double[][] M) {
		// to find the main colonne
		int MainC = 0;
		double d = M[index][0];
		for (int i = 0; i < index + N; i++) {
			if (M[index][i] > d) {
				d = M[index][i];
				MainC = i;
			}
		}
		return MainC;
	}

	public boolean Check(double[][] M, int id) {
		// dans la main colonne, si tous <0: deja mini
		boolean check = false;

		for (int j = 0; j < index; j++) {
			if (M[j][id] > 0) {
				check = true;
			}
		}
		return check;
	}

	public int MainLigne(double[][] M, int id) {
		// quand on sait le main colonne est id eme, cherche main ligne
		double d = 1000000; // valeur initiale=+INFINIY
		int ligne = 0;
		for (int j = 0; j < index; j++) {
			if (M[j][id] > 0) {
				if (d > M[j][N + index] / M[j][id]) {
					d = M[j][N + index] / M[j][id];
					ligne = j;
				}
			}

		}
		return ligne;

	}

	public Invariant PreSimplication(Invariant inv) {
		// assort variables if assumtion of inv not verified
		return null;
	}
}
